package TuringMachine;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class TuringMachine {

	private Map<Integer, Integer> tape;
	
	private Map<String, Map<Integer, Movement>> nodes;
	
	private Integer currentPosition;
	
	private String currentState;
	
	private int minPosition;
	private int maxPosition;
	
	public TuringMachine() {
		this.nodes = new HashMap<String, Map<Integer, Movement>>();
		this.tape = new HashMap<Integer, Integer>();
		this.minPosition = 0;
		this.currentPosition = 0;
		this.currentState = null;
		
	}
	
	public static void main(String[] args) {
		String filePath=null;
		if(args.length !=0)
			filePath=args[0];
		if(filePath==null){
			System.err.println("Faltan parametros!");
			System.exit(3);
		}
		TuringMachine tm = new TuringMachine();
		Parser parser= new Parser();
		File file= new File(filePath);
		boolean error=true;
		
		try {
			error=parser.readFile(file, tm);
		} catch (IOException e) {
			System.err.println("Error al abrir el archivo solicitado!");
		}
		if(error)
			return;
		
		tm.tape=parser.createTape();
		if(tm.tape==null)
			return;
		
		tm.execute();
		tm.printTape();
	}
	
	public boolean addNode(String currentState, Map<Integer, Movement> node) {
		if(this.nodes.containsKey(currentState)){
			if(this.nodes.get(currentState).containsKey(node.keySet().toArray()[0])){
				System.err.println("La maquina de turing es invalida, posee transicion ambigua");
				System.exit(4);
			}
			this.nodes.get(currentState).putAll(node);
			return true;
		}else{
			if(this.currentState==null)
				this.currentState=currentState;
			this.nodes.put(currentState, node);
			return true;
		}
	}
	
	public void execute() {
		do {
			Integer appointedValue = this.tape.get(this.currentPosition);
			if(appointedValue == null) {
				this.tape.put(this.currentPosition, 0);
				appointedValue = 0;
			}
			
			Map<Integer, Movement> next = this.nodes.get(this.currentState);
			if(next == null) {
				return;
			}
			
			Movement movement = next.get(appointedValue);
			if(movement == null) {
				return;
			}
			
			String action = movement.getAction();
			
			if(action.equals("<")) {
				this.currentPosition --;
				if(this.currentPosition <= this.minPosition) {
					this.minPosition = this.currentPosition;
				}
			} else if(action.equals(">")) {
				this.currentPosition ++;
				if(this.currentPosition >= this.maxPosition) {
					this.maxPosition = this.currentPosition;
				}
			} else if(action.equals("0") || action.equals("1") || action.equals("2")) {
				this.tape.put(currentPosition, Integer.valueOf(action));
			}
			this.currentState = movement.getNextState();
		} while(true);
	}
	
	private void printTape() {
		for(int i = this.minPosition; i <= this.maxPosition; i++) {
			System.out.print(tape.get(i));
		}
		System.out.println("");
	}

	public Map<Integer, Integer> getTape() {
		return tape;
	}
	
	public void setTape(Map<Integer, Integer> tape) {
		this.tape = tape;
	}

	public Map<String, Map<Integer, Movement>> getNodes() {
		return nodes;
	}

	public void setCurrentState(String currentState) {
		this.currentState = currentState;
	}

	public int getMinPosition() {
		return minPosition;
	}

	public int getMaxPosition() {
		return maxPosition;
	}
}
